// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
// This source file is part of the Cangjie project, licensed under Apache-2.0
// with Runtime Library Exception.
//
// See https://cangjie-lang.cn/pages/LICENSE for license information.

#include "NodeCast.h"
#include "Rules/RefExprMatchRule.h"

#include "Rules/Rule.h"

using namespace Cangjie::AST;

namespace CangjieMigrator::Rules {

RefExprMatchRule::RefExprMatchRule(std::string package, std::string identifier)
    : package(std::move(package)), identifier(std::move(identifier))
{}

MatchRule::Type RefExprMatchRule::GetType() const
{
    return Type::RefExpr;
}

std::unique_ptr<ExtractedInfo> RefExprMatchRule::ExtractInfo(const Node &node, PositionRange range)
{
    if (node.astKind != Cangjie::AST::ASTKind::REF_EXPR) {
        return nullptr;
    }
    const auto &refExpr = Cast<Cangjie::AST::ASTKind::REF_EXPR>(node);

    const auto &ref = refExpr.ref;
    const auto &target = ref.target;
    if (!target) {
        return nullptr;
    }

    auto package = target->fullPackageName;
    if (package == "default") { // Local Variable
        return nullptr;
    }

    auto identifier = ref.identifier.GetRawText();

    if (refExpr.leftAnglePos.IsZero()) {
        return std::make_unique<RefExprExtractedInfo>(range, refExpr, package, identifier);
    }

    const auto leftAnglePos = refExpr.GetMacroCallPos(refExpr.leftAnglePos);
    if (leftAnglePos.fileID != range.start.fileID) {
        return nullptr;
    }

    return std::make_unique<RefExprExtractedInfo>(
        PositionRange(range.start, leftAnglePos), refExpr, package, identifier);
}

bool RefExprMatchRule::MatchConditions(const ExtractedInfo *info)
{
    const auto refExprInfo = dynamic_cast<const RefExprExtractedInfo *>(info);
    if (!refExprInfo) {
        return false;
    }

    if (refExprInfo->package != package || refExprInfo->identifier != identifier) {
        return false;
    }

    return true;
}

std::vector<Actions::Action> RefExprMatchRule::GenerateAction(
    UpdateInstance::File &file, const ExtractedInfo &info, const std::string &update, const Rule *rule) const
{
    if (update.empty()) {
        return {};
    }
    const auto i = dynamic_cast<const RefExprExtractedInfo &>(info);
    return {Actions::Replace(i.replacePosition, update, rule)};
}

std::unique_ptr<MatchRule> RefExprMatchRule::TryBuild(const TomlConfig &config)
{
    if (config.title != "RefExpr") {
        return nullptr;
    }
    GET_VALUE_IF_EMPTY_RETURN_NULL(config, package);
    GET_VALUE_IF_EMPTY_RETURN_NULL(config, identifier);
    return std::make_unique<RefExprMatchRule>(package, identifier);
}

} // namespace CangjieMigrator::Rules
